/**
 * hash.js
 *
 * Copyright (C) 2012 Emmanuel Garcia
 * MIT Licensed
 *
 * ****************************************
 *
 * Hash.pushState(true);
 *
 * Hash.on('/page/([0-9]+)$',
 *	{yep: function(path, parts) { }, nop: function() { }},
 *	'Page $1');
 *
 * Hash.go('/page/1');
 **/

var hashes = {},
  regexp = {},
  history = [],
  freq = 100,
  num = 0,
  pushState = false,
  timer = null,
  currentUrl = null,
  freeze = function (obj) {
    if (Object.freeze) return Object.freeze(obj);
    return obj;
  },
  getHashParts = function () {
    return window.location.href.split('#');
  },
  startTimer = function () {
    if (!timer)
      timer = setInterval(function () {
        if (num > 0 && currentUrl != window.location.href) {
          currentUrl = window.location.href;
          window.Hash.check();
        }
      }, freq);
  },
  stopTimer = function () {
    if (timer) {
      clearInterval(timer);
      timer = null;
    }
  };

window.Hash = freeze({
  pushState: function (yes) {
    if (window.history && window.history.pushState) pushState = yes;
    return this;
  },

  fragment: function () {
    var hash = getHashParts();
    return pushState
      ? window.location.pathname + (hash[1] ? '#' + hash[1] : '')
      : hash[1] || '';
  },

  get: function (path, params) {
    var p,
      fragment = '',
      parameters = [];
    for (p in params) {
      if (!Object.prototype.hasOwnProperty(p)) continue;
      parameters.push(
        encodeURIComponent(p) + '=' + encodeURIComponent(params[p])
      );
    }
    if (parameters.length > 0) parameters = '?' + parameters.join('&');
    return pushState
      ? path + parameters
      : getHashParts()[0] + '#' + path + parameters;
  },

  go: function (hash, params) {
    if (this.fragment() != hash) {
      var to = this.get(hash, params);
      if (pushState) window.history.pushState(null, document.title, to);
      else window.location.href = to;
    }
    return this;
  },

  update: function () {
    currentUrl = window.location.href;
    return this;
  },

  on: function (hash, callback, title) {
    if (!hashes[hash])
      hashes[hash] = {
        title: title,
        listeners: []
      };

    hashes[hash].listeners.push(callback);
    num++;
    startTimer();
    return this;
  },

  check: function () {
    var i,
      hash,
      parts,
      fragment = this.fragment();
    for (hash in hashes) {
      if (!Object.prototype.hasOwnProperty.call(hashes, hash)) continue;
      hashes[hash].regexp = hashes[hash].regexp || new RegExp(hash);
      if ((parts = hashes[hash].regexp.exec(fragment))) {
        if (hashes[hash].title) document.title = hashes[hash].title;
        for (i = 0; i < hashes[hash].listeners.length; i++)
          if (hashes[hash].listeners[i].yep)
            hashes[hash].listeners[i].yep(fragment, parts);
      } else {
        for (i = 0; i < hashes[hash].listeners.length; i++)
          if (hashes[hash].listeners[i].nop)
            hashes[hash].listeners[i].nop(fragment);
      }
    }
    return this;
  }
});

export default Hash;
